package IO;

//和InputStream相反，OutputStream是Java标准库提供的最基本的输出流。
//和InputStream类似，OutputStream也是抽象类，它是所有输出流的超类。这个抽象类定义的一个最重要的方法就是void write(int b)，签名如下：
//public abstract void write(int b) throws IOException;
//这个方法会写入一个字节到输出流。要注意的是，虽然传入的是int参数，但只会写入一个字节，即只写入int最低8位表示字节的部分（相当于b & 0xff）。
//和InputStream类似，OutputStream也提供了close()方法关闭输出流，以便释放系统资源。要特别注意：OutputStream还提供了一个flush()方法，它的目的是将缓
//冲区的内容真正输出到目的地。
//
//为什么要有flush()？因为向磁盘、网络写入数据的时候，出于效率的考虑，操作系统并不是输出一个字节就立刻写入到文件或者发送到网络，而是把输出的字节先放到内存的一个
//缓冲区里（本质上就是一个byte[]数组），等到缓冲区写满了，再一次性写入文件或者网络。对于很多IO设备来说，一次写一个字节和一次写1000个字节，花费的时间几乎是完全
//一样的，所以OutputStream有个flush()方法，能强制把缓冲区内容输出。
//
//通常情况下，我们不需要调用这个flush()方法，因为缓冲区写满了OutputStream会自动调用它，并且，在调用close()方法关闭OutputStream之前，也会自动调
//用flush()方法。
//
//但是，在某些情况下，我们必须手动调用flush()方法。举个栗子：
//
//小明正在开发一款在线聊天软件，当用户输入一句话后，就通过OutputStream的write()方法写入网络流。小明测试的时候发现，发送方输入后，接收方根本收不到任何信息，
//怎么肥四？
//
//原因就在于写入网络流是先写入内存缓冲区，等缓冲区满了才会一次性发送到网络。如果缓冲区大小是4K，则发送方要敲几千个字符后，操作系统才会把缓冲区的内容发送出去，
//这个时候，接收方会一次性收到大量消息。
//
//解决办法就是每输入一句话后，立刻调用flush()，不管当前缓冲区是否已满，强迫操作系统把缓冲区的内容立刻发送出去。
//
//实际上，InputStream也有缓冲区。例如，从FileInputStream读取一个字节时，操作系统往往会一次性读取若干字节到缓冲区，并维护一个指针指向未读的缓冲区。然后，每
//次我们调用int read()读取下一个字节时，可以直接返回缓冲区的下一个字节，避免每次读一个字节都导致IO操作。当缓冲区全部读完后继续调用read()，则会触发操作系统的
//下一次读取并再次填满缓冲区。
//
//FileOutputStream
//我们以FileOutputStream为例，演示如何将若干个字节写入文件流：
//
//public void writeFile() throws IOException {
//    OutputStream output = new FileOutputStream("out/readme.txt");
//    output.write(72); // H
//    output.write(101); // e
//    output.write(108); // l
//    output.write(108); // l
//    output.write(111); // o
//    output.close();
//}
//每次写入一个字节非常麻烦，更常见的方法是一次性写入若干字节。这时，可以用OutputStream提供的重载方法void write(byte[])来实现：
//
//public void writeFile() throws IOException {
//    OutputStream output = new FileOutputStream("out/readme.txt");
//    output.write("Hello".getBytes("UTF-8")); // Hello
//    output.close();
//}
//和InputStream一样，上述代码没有考虑到在发生异常的情况下如何正确地关闭资源。写入过程也会经常发生IO错误，例如，磁盘已满，无权限写入等等。我们需要
//用try(resource)来保证OutputStream在无论是否发生IO错误的时候都能够正确地关闭：
//
//public void writeFile() throws IOException {
//    try (OutputStream output = new FileOutputStream("out/readme.txt")) {
//        output.write("Hello".getBytes("UTF-8")); // Hello
//    } // 编译器在此自动为我们写入finally并调用close()
//}
//
//《阻塞》
//和InputStream一样，OutputStream的write()方法也是阻塞的。
//
//《OutputStream实现类》
//用FileOutputStream可以从文件获取输出流，这是OutputStream常用的一个实现类。此外，ByteArrayOutputStream可以在内存中模拟一个OutputStream：

//import java.io.*;
//public class 使用OutputStream {
//    public static void main(String[] args) throws IOException {
//        byte[] data;
//        try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
//            output.write("Hello ".getBytes("UTF-8"));
//            output.write("world!".getBytes("UTF-8"));
//            data = output.toByteArray();
//        }
//        System.out.println(new String(data, "UTF-8"));
//    }
//}

//ByteArrayOutputStream实际上是把一个byte[]数组在内存中变成一个OutputStream，虽然实际应用不多，但测试的时候，可以用它来构造一个OutputStream。
//
//同时操作多个AutoCloseable资源时，在try(resource) { ... }语句中可以同时写出多个资源，用;隔开。例如，同时读写两个文件：
//
//// 读取input.txt，写入output.txt:
//try (InputStream input = new FileInputStream("input.txt");
//     OutputStream output = new FileOutputStream("output.txt"))
//{
//    input.transferTo(output); // transferTo的作用是?
//}
//练习
//请利用InputStream和OutputStream，编写一个复制文件的程序，它可以带参数运行：
//
//java CopyFile.java source.txt copy.txt
//从下载练习：CopyFile练习 （推荐使用IDE练习插件快速下载）
//
//小结
//Java标准库的java.io.OutputStream定义了所有输出流的超类：
//
//FileOutputStream实现了文件流输出；
//
//ByteArrayOutputStream在内存中模拟一个字节流输出。
//
//某些情况下需要手动调用OutputStream的flush()方法来强制输出缓冲区。
//
//总是使用try(resource)来保证OutputStream正确关闭。

import java.io.*;

//public class CopyFile {
public class 使用OutputStream {
	public static void main(String[] args) throws IOException {
//		if (args.length != 2) {
//			System.err.println("Usage:\n  java CopyFile.java <source> <target>");
//			System.exit(1);
//		}
//		copy(args[0], args[1]);
//	}
	 args=new String[2];
	 args[0]="readme.txt";//源文件
	 args[1]="readme1.txt";//目标文件
//	if (args.length != 2) {
//		System.err.println("Usage:\n  java CopyFile.java <source> <target>");
//		System.exit(1);
//	}
	copy(args[0], args[1]);
}
	static void copy(String source, String target) throws IOException {
		// 友情提示：测试时请使用无关紧要的文件
		// TODO:
		try (InputStream input = new FileInputStream(source);
			     OutputStream output = new FileOutputStream(target))
			{
			    input.transferTo(output); 
			    System.out.println("复制成功");
			}
	}
}


